package com.free.bsf.core.util;

import com.free.bsf.core.base.BsfException;
import lombok.Getter;
import lombok.Setter;
import lombok.val;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;


/**
 * @author: chejiangyi
 * @version: 2019-07-01 17:56 Web 上下文操作
 **/
public class WebUtils {
    private static final ThreadLocal<WebContext> threadContext = new ThreadLocal<WebContext>();

    public static WebContext getContext() {
        WebContext webContext = threadContext.get();
        return webContext;
    }

    public static HttpServletRequest getRequest() {
        WebContext webContext = getContext();
        return webContext == null ? null : webContext.request;
    }

    public static HttpServletResponse getResponse() {
        WebContext webContext = getContext();
        return webContext == null ? null : webContext.response;
    }

    public static void bindContext(HttpServletRequest request, HttpServletResponse response) {
        threadContext.set(new WebContext(request, response));
    }

    public static void clearContext() {
        threadContext.remove();
    }

    public static class WebContext {
        @Getter
        private HttpServletRequest request;
        @Getter
        private HttpServletResponse response;
        @Getter @Setter
        private Object controller;
        @Getter @Setter
        private Method method;

        public WebContext(HttpServletRequest request, HttpServletResponse response) {
            this.request = request;
            this.response = response;
        }

    }

    public static String getBaseUrl() {
        if (!ContextUtils.isWeb()) {
            return "";
        }
        val webServer = ContextUtils.getConfigurableWebServerApplicationContext().getWebServer();
        if (webServer == null) {
            return "";
        }
        return "http://" + NetworkUtils.getIpAddress() + ":" + webServer.getPort() +
                PropertyUtils.getPropertyCache("server.servlet.context-path", "");
    }

    public static String getRequestURI() {
        return getRequest()==null ? null : getRequest().getRequestURI();
    }

    public static Map<ThreadLocal, Object> getThreadLocalMap(Thread thread){
        Map<ThreadLocal, Object> threadLocals = new HashMap<>();
        try{
            Field threadLocalsField = Thread.class.getDeclaredField("threadLocals");
            threadLocalsField.setAccessible(true);
            Object threadLocalMap = threadLocalsField.get(thread);
            if(threadLocalMap!=null) {
                Field tableField = threadLocalMap.getClass().getDeclaredField("table");
                tableField.setAccessible(true);
                Object[] table = (Object[]) tableField.get(threadLocalMap);
                if(table!=null) {
                    for (int i = 0; i < table.length; i++) {
                        Object entry = table[i];
                        if (entry != null) {
                            WeakReference<ThreadLocal> threadLocalRef = (WeakReference<ThreadLocal>) entry;
                            ThreadLocal threadLocal = threadLocalRef.get();
                            if (threadLocal != null) {
                                Object threadLocalValue = threadLocal.get();
                                threadLocals.put(threadLocal, threadLocalValue);
                            }
                        }
                    }
                }
            }
        }catch(Exception e){
            throw new BsfException(e);
        }
        return threadLocals;
    }
}
